<script type="text/jsx">
    import emitter from 'element-ui/src/mixins/emitter';
    import Migrating from 'element-ui/src/mixins/migrating';
    import Menubar from 'element-ui/src/utils/menu/aria-menubar';
    import {addClass, removeClass, hasClass} from 'element-ui/src/utils/dom';

    export default {
        name: 'ElMenu',

        render(h) {
            const component = (
                <ul
                    role="menubar"
                    key={+this.collapse}
                    style={{backgroundColor: this.backgroundColor || ''}}
                    class={{
                        'el-menu--horizontal': this.mode === 'horizontal',
                        'el-menu--collapse': this.collapse,
                        "el-menu": true
                    }}
                >
                    {this.$slots.default}
                </ul>
            );

            if (this.collapseTransition) {
                return (
                    <el-menu-collapse-transition>
                        {component}
                    </el-menu-collapse-transition>
                );
            } else {
                return component;
            }
        },

        componentName: 'ElMenu',

        mixins: [emitter, Migrating],

        provide() {
            return {
                rootMenu: this
            };
        },

        components: {
            'el-menu-collapse-transition': {
                functional: true,
                render(createElement, context) {
                    const data = {
                        props: {
                            mode: 'out-in'
                        },
                        on: {
                            beforeEnter(el) {
                                el.style.opacity = 0.2;
                            },

                            enter(el) {
                                addClass(el, 'el-opacity-transition');
                                el.style.opacity = 1;
                            },

                            afterEnter(el) {
                                removeClass(el, 'el-opacity-transition');
                                el.style.opacity = '';
                            },

                            beforeLeave(el) {
                                if (!el.dataset) el.dataset = {};

                                if (hasClass(el, 'el-menu--collapse')) {
                                    removeClass(el, 'el-menu--collapse');
                                    el.dataset.oldOverflow = el.style.overflow;
                                    el.dataset.scrollWidth = el.clientWidth;
                                    addClass(el, 'el-menu--collapse');
                                } else {
                                    addClass(el, 'el-menu--collapse');
                                    el.dataset.oldOverflow = el.style.overflow;
                                    el.dataset.scrollWidth = el.clientWidth;
                                    removeClass(el, 'el-menu--collapse');
                                }

                                el.style.width = el.scrollWidth + 'px';
                                el.style.overflow = 'hidden';
                            },

                            leave(el) {
                                addClass(el, 'horizontal-collapse-transition');
                                el.style.width = el.dataset.scrollWidth + 'px';
                            }
                        }
                    };
                    return createElement('transition', data, context.children);
                }
            }
        },

        props: {
            mode: {
                type: String,
                default: 'vertical'
            },
            defaultActive: {
                type: String,
                default: ''
            },
            defaultOpeneds: Array,
            uniqueOpened: Boolean,
            router: Boolean,
            menuTrigger: {
                type: String,
                default: 'hover'
            },
            collapse: Boolean,
            backgroundColor: String,
            textColor: String,
            activeTextColor: String,
            collapseTransition: {
                type: Boolean,
                default: true
            }
        },
        data() {
            return {
                activeIndex: this.defaultActive,
                openedMenus: (this.defaultOpeneds && !this.collapse) ? this.defaultOpeneds.slice(0) : [],
                items: {},
                submenus: {}
            };
        },
        computed: {
            hoverBackground() {
                return this.backgroundColor ? this.mixColor(this.backgroundColor, 0.2) : '';
            },
            isMenuPopup() {
                return this.mode === 'horizontal' || (this.mode === 'vertical' && this.collapse);
            }
        },
        watch: {
            defaultActive(value) {
                if (!this.items[value]) {
                    this.activeIndex = null
                }
                this.updateActiveIndex(value)
            },

            defaultOpeneds(value) {
                if (!this.collapse) {
                    this.openedMenus = value;
                }
            },

            collapse(value) {
                if (value) this.openedMenus = [];
                this.broadcast('ElSubmenu', 'toggle-collapse', value);
            }
        },
        methods: {
            updateActiveIndex(val) {
                const item = this.items[val] || this.items[this.activeIndex] || this.items[this.defaultActive];
                if (item) {
                    this.activeIndex = item.index;
                    this.initOpenedMenu();
                } else {
                    this.activeIndex = null;
                }
            },

            getMigratingConfig() {
                return {
                    props: {
                        'theme': 'theme is removed.'
                    }
                };
            },
            getColorChannels(color) {
                color = color.replace('#', '');
                if (/^[0-9a-fA-F]{3}$/.test(color)) {
                    color = color.split('');
                    for (let i = 2; i >= 0; i--) {
                        color.splice(i, 0, color[i]);
                    }
                    color = color.join('');
                }
                if (/^[0-9a-fA-F]{6}$/.test(color)) {
                    return {
                        red: parseInt(color.slice(0, 2), 16),
                        green: parseInt(color.slice(2, 4), 16),
                        blue: parseInt(color.slice(4, 6), 16)
                    };
                } else {
                    return {
                        red: 255,
                        green: 255,
                        blue: 255
                    };
                }
            },
            mixColor(color, percent) {
                let {red, green, blue} = this.getColorChannels(color);
                if (percent > 0) { // shade given color
                    red *= 1 - percent;
                    green *= 1 - percent;
                    blue *= 1 - percent;
                } else { // tint given color
                    red += (255 - red) * percent;
                    green += (255 - green) * percent;
                    blue += (255 - blue) * percent;
                }
                return `rgb(${ Math.round(red) }, ${ Math.round(green) }, ${ Math.round(blue) })`;
            },
            addItem(item) {
                this.$set(this.items, item.index, item);
            },
            removeItem(item) {
                delete this.items[item.index];
            },
            addSubmenu(item) {
                this.$set(this.submenus, item.index, item);
            },
            removeSubmenu(item) {
                delete this.submenus[item.index];
            },
            openMenu(index, indexPath) {
                let openedMenus = this.openedMenus;
                if (openedMenus.indexOf(index) !== -1) return;
                // 将不在该菜单路径下的其余菜单收起
                // collapse all menu that are not under current menu item
                if (this.uniqueOpened) {
                    this.openedMenus = openedMenus.filter(index => {
                        return indexPath.indexOf(index) !== -1;
                    });
                }
                this.openedMenus.push(index);
            },
            closeMenu(index) {
                const i = this.openedMenus.indexOf(index);
                if (i !== -1) {
                    this.openedMenus.splice(i, 1);
                }
            },
            handleSubmenuClick(submenu) {
                const {index, indexPath} = submenu;
                let isOpened = this.openedMenus.indexOf(index) !== -1;

                if (isOpened) {
                    this.closeMenu(index);
                    this.$emit('close', index, indexPath);
                } else {
                    this.openMenu(index, indexPath);
                    this.$emit('open', index, indexPath);
                }
            },
            handleItemClick(item) {
                const {index, indexPath} = item;
                const oldActiveIndex = this.activeIndex;
                const hasIndex = item.index !== null;

                if (hasIndex) {
                    this.activeIndex = item.index;
                }

                this.$emit('select', index, indexPath, item);

                if (this.mode === 'horizontal' || this.collapse) {
                    this.openedMenus = [];
                }

                if (this.router && hasIndex) {
                    this.routeToItem(item, (error) => {
                        this.activeIndex = oldActiveIndex;
                        if (error) {
                            // vue-router 3.1.0+ push/replace cause NavigationDuplicated error
                            // https://github.com/ElemeFE/element/issues/17044
                            if (error.name === 'NavigationDuplicated') return
                            console.error(error)
                        }
                    });
                }
            },
            // 初始化展开菜单
            // initialize opened menu
            initOpenedMenu() {
                const index = this.activeIndex;
                const activeItem = this.items[index];
                if (!activeItem || this.mode === 'horizontal' || this.collapse) return;

                let indexPath = activeItem.indexPath;

                // 展开该菜单项的路径上所有子菜单
                // expand all submenus of the menu item
                indexPath.forEach(index => {
                    let submenu = this.submenus[index];
                    submenu && this.openMenu(index, submenu.indexPath);
                });
            },
            routeToItem(item, onError) {
                let route = item.route || item.index;
                try {
                    this.$router.push(route, () => {
                    }, onError);
                } catch (e) {
                    console.error(e);
                }
            },
            open(index) {
                const {indexPath} = this.submenus[index.toString()];
                indexPath.forEach(i => this.openMenu(i, indexPath));
            },
            close(index) {
                this.closeMenu(index);
            }
        },
        mounted() {
            this.initOpenedMenu();
            this.$on('item-click', this.handleItemClick);
            this.$on('submenu-click', this.handleSubmenuClick);
            if (this.mode === 'horizontal') {
                new Menubar(this.$el); // eslint-disable-line
            }
            this.$watch('items', this.updateActiveIndex);
        }
    };
</script>
